package services

import (
	"context"
	"errors"
	"sort"
	"time"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo/options"

	"zwai-app/db"
	"zwai-app/models"
)

// ArticleWithAuthor 是对外返回的 DTO，包含文章基本信息、作者名、评论数、以及分类 ID
type ArticleWithAuthor struct {
	ID           string    `json:"id"`
	Title        string    `json:"title"`
	Description  string    `json:"description"`
	Content      string    `json:"content"`
	Tags         []string  `json:"tags"`
	Status       string    `json:"status"`
	Visibility   string    `json:"visibility"`
	Likes        int       `json:"likes"`
	Views        int       `json:"views"`
	CommentCount int64     `json:"commentCount"`
	CreatedAt    time.Time `json:"createdAt"`
	UpdatedAt    time.Time `json:"updatedAt"`
	AuthorID     string    `json:"authorId"`
	AuthorName   string    `json:"authorName"`
	CategoryID   string    `json:"categoryId"` // ← 新增分类字段
}

// ArticlePage 专门用于分页接口返回的数据结构
type ArticlePage struct {
	Items      []ArticleWithAuthor `json:"items"`
	TotalCount int64               `json:"totalCount"`
	Page       int                 `json:"page"`
	PageSize   int                 `json:"pageSize"`
}

// GetPublicArticlesPage 返回“公开且已通过”文章的分页列表，支持按 categoryID 过滤
func GetPublicArticlesPage(
	ctx context.Context,
	page, size int,
	categoryID *primitive.ObjectID,
) (ArticlePage, error) {
	coll := db.Client.Database(db.DBName).Collection("Article")

	// 构造过滤条件
	filter := bson.M{"status": "approved", "visibility": "public"}
	if categoryID != nil {
		filter["categoryId"] = *categoryID
	}

	// 1) 查询总数
	total, err := coll.CountDocuments(ctx, filter)
	if err != nil {
		return ArticlePage{}, err
	}

	// 2) 分页 & 创建时间倒序
	findOpts := options.Find().
		SetSkip(int64((page - 1) * size)).
		SetLimit(int64(size)).
		SetSort(bson.D{{Key: "createdAt", Value: -1}})

	cursor, err := coll.Find(ctx, filter, findOpts)
	if err != nil {
		return ArticlePage{}, err
	}
	defer cursor.Close(ctx)

	var items []ArticleWithAuthor
	for cursor.Next(ctx) {
		// 解码带 categoryId 的文档
		var art struct {
			ID          primitive.ObjectID   `bson:"_id"`
			AuthorID    primitive.ObjectID   `bson:"authorId"`
			Title       string               `bson:"title"`
			Description string               `bson:"description"`
			Content     string               `bson:"content"`
			Tags        []string             `bson:"tags"`
			Status      string               `bson:"status"`
			Visibility  string               `bson:"visibility"`
			Likes       int                  `bson:"likes"`
			Views       int                  `bson:"views"`
			Comments    []primitive.ObjectID `bson:"comments"`
			CreatedAt   primitive.DateTime   `bson:"createdAt"`
			UpdatedAt   primitive.DateTime   `bson:"updatedAt"`
			CategoryID  primitive.ObjectID   `bson:"categoryId"`
		}
		if err := cursor.Decode(&art); err != nil {
			continue
		}

		// 查作者昵称
		userColl := db.Client.Database(db.DBName).Collection("User")
		var u struct {
			Username string `bson:"username"`
		}
		authorName := "未知作者"
		if err := userColl.FindOne(ctx, bson.M{"_id": art.AuthorID}).Decode(&u); err == nil {
			authorName = u.Username
		}

		// 评论数 = len(Comments)
		commentCount := int64(len(art.Comments))

		items = append(items, ArticleWithAuthor{
			ID:           art.ID.Hex(),
			Title:        art.Title,
			Description:  art.Description,
			Content:      art.Content,
			Tags:         art.Tags,
			Status:       art.Status,
			Visibility:   art.Visibility,
			Likes:        art.Likes,
			Views:        art.Views,
			CommentCount: commentCount,
			CreatedAt:    art.CreatedAt.Time(),
			UpdatedAt:    art.UpdatedAt.Time(),
			AuthorID:     art.AuthorID.Hex(),
			AuthorName:   authorName,
			CategoryID:   art.CategoryID.Hex(), // ← 填充分类 ID
		})
	}

	return ArticlePage{
		Items:      items,
		TotalCount: total,
		Page:       page,
		PageSize:   size,
	}, nil
}

// GetAllArticlesPage 返回“全部”已通过公开文章分页列表，最新发布在前
func GetAllArticlesPage(
	ctx context.Context,
	page, size int,
	categoryID *primitive.ObjectID, // ← 新增参数
) (ArticlePage, error) {
	coll := db.Client.Database(db.DBName).Collection("Article")
	filter := bson.M{"status": "approved", "visibility": "public"}

	if categoryID != nil {
		filter["categoryId"] = *categoryID
	}

	total, err := coll.CountDocuments(ctx, filter)
	if err != nil {
		return ArticlePage{}, err
	}

	opts := options.Find().
		SetSkip(int64((page - 1) * size)).
		SetLimit(int64(size)).
		SetSort(bson.D{{Key: "createdAt", Value: -1}})

	cursor, err := coll.Find(ctx, filter, opts)
	if err != nil {
		return ArticlePage{}, err
	}
	defer cursor.Close(ctx)

	var items []ArticleWithAuthor
	for cursor.Next(ctx) {
		var art struct {
			ID          primitive.ObjectID   `bson:"_id"`
			AuthorID    primitive.ObjectID   `bson:"authorId"`
			Title       string               `bson:"title"`
			Description string               `bson:"description"`
			Content     string               `bson:"content"`
			Tags        []string             `bson:"tags"`
			Status      string               `bson:"status"`
			Visibility  string               `bson:"visibility"`
			Likes       int                  `bson:"likes"`
			Views       int                  `bson:"views"`
			Comments    []primitive.ObjectID `bson:"comments"`
			CreatedAt   primitive.DateTime   `bson:"createdAt"`
			UpdatedAt   primitive.DateTime   `bson:"updatedAt"`
			CategoryID  primitive.ObjectID   `bson:"categoryId"`
		}
		if err := cursor.Decode(&art); err != nil {
			continue
		}

		// 作者名
		userColl := db.Client.Database(db.DBName).Collection("User")
		var u struct {
			Username string `bson:"username"`
		}
		authorName := "未知作者"
		if err := userColl.FindOne(ctx, bson.M{"_id": art.AuthorID}).Decode(&u); err == nil {
			authorName = u.Username
		}

		commentCount := int64(len(art.Comments))

		items = append(items, ArticleWithAuthor{
			ID:           art.ID.Hex(),
			Title:        art.Title,
			Description:  art.Description,
			Content:      art.Content,
			Tags:         art.Tags,
			Status:       art.Status,
			Visibility:   art.Visibility,
			Likes:        art.Likes,
			Views:        art.Views,
			CommentCount: commentCount,
			CreatedAt:    art.CreatedAt.Time(),
			UpdatedAt:    art.UpdatedAt.Time(),
			AuthorID:     art.AuthorID.Hex(),
			AuthorName:   authorName,
			CategoryID:   art.CategoryID.Hex(),
		})
	}

	return ArticlePage{
		Items:      items,
		TotalCount: total,
		Page:       page,
		PageSize:   size,
	}, nil
}

// GetHotArticles 返回“热门”文章，按 点赞→评论→浏览 排序，限最多 limit 条
func GetHotArticles(ctx context.Context, limit int) ([]ArticleWithAuthor, error) {
	coll := db.Client.Database(db.DBName).Collection("Article")
	filter := bson.M{"status": "approved", "visibility": "public"}

	cursor, err := coll.Find(ctx, filter, options.Find())
	if err != nil {
		return nil, err
	}
	defer cursor.Close(ctx)

	var list []ArticleWithAuthor
	for cursor.Next(ctx) {
		var art struct {
			ID          primitive.ObjectID   `bson:"_id"`
			AuthorID    primitive.ObjectID   `bson:"authorId"`
			Title       string               `bson:"title"`
			Description string               `bson:"description"`
			Content     string               `bson:"content"`
			Tags        []string             `bson:"tags"`
			Likes       int                  `bson:"likes"`
			Views       int                  `bson:"views"`
			Comments    []primitive.ObjectID `bson:"comments"`
			CreatedAt   primitive.DateTime   `bson:"createdAt"`
			UpdatedAt   primitive.DateTime   `bson:"updatedAt"`
			CategoryID  primitive.ObjectID   `bson:"categoryId"`
		}
		if err := cursor.Decode(&art); err != nil {
			continue
		}

		// 作者名
		userColl := db.Client.Database(db.DBName).Collection("User")
		var u struct {
			Username string `bson:"username"`
		}
		authorName := "未知作者"
		if err := userColl.FindOne(ctx, bson.M{"_id": art.AuthorID}).Decode(&u); err == nil {
			authorName = u.Username
		}

		commentCount := int64(len(art.Comments))

		list = append(list, ArticleWithAuthor{
			ID:           art.ID.Hex(),
			Title:        art.Title,
			Description:  art.Description,
			Content:      art.Content,
			Tags:         art.Tags,
			Status:       "approved",
			Visibility:   "public",
			Likes:        art.Likes,
			Views:        art.Views,
			CommentCount: commentCount,
			CreatedAt:    art.CreatedAt.Time(),
			UpdatedAt:    art.UpdatedAt.Time(),
			AuthorID:     art.AuthorID.Hex(),
			AuthorName:   authorName,
			CategoryID:   art.CategoryID.Hex(),
		})
	}

	// 排序：likes desc, commentCount desc, views desc
	sort.Slice(list, func(i, j int) bool {
		if list[i].Likes != list[j].Likes {
			return list[i].Likes > list[j].Likes
		}
		if list[i].CommentCount != list[j].CommentCount {
			return list[i].CommentCount > list[j].CommentCount
		}
		return list[i].Views > list[j].Views
	})

	if len(list) > limit {
		list = list[:limit]
	}
	return list, nil
}

// GetUserArticles 返回某个用户的所有文章（含 pending/rejected），并附带作者昵称
func GetUserArticles(ctx context.Context, userIDStr string) ([]ArticleWithAuthor, error) {
	// 1. 把传进来的 userID 字符串转 ObjectID
	uid, err := primitive.ObjectIDFromHex(userIDStr)
	if err != nil {
		return nil, errors.New("invalid user ID")
	}
	// 2. 从 Article 集合里查
	artColl := db.Client.Database(db.DBName).Collection("Article")
	cursor, err := artColl.Find(ctx, bson.M{"authorId": uid})
	if err != nil {
		return nil, err
	}
	defer cursor.Close(ctx)

	// 3. 准备返回切片
	var out []ArticleWithAuthor
	userColl := db.Client.Database(db.DBName).Collection("User")
	for cursor.Next(ctx) {
		var art models.Article
		if err := cursor.Decode(&art); err != nil {
			continue
		}

		// 4. 查一下作者（其实就是自己）的用户名
		var author models.User
		authorName := "未知作者"
		if err := userColl.FindOne(ctx, bson.M{"_id": art.AuthorID}).Decode(&author); err == nil {
			authorName = author.Username
		}

		// 5. 拼装 DTO（记得补上 CategoryID、CommentCount 等字段）
		out = append(out, ArticleWithAuthor{
			ID:           art.ID.Hex(),
			Title:        art.Title,
			Description:  art.Description,
			Content:      art.Content,
			Tags:         art.Tags,
			Status:       art.Status,
			Visibility:   art.Visibility,
			Likes:        art.Likes,
			Views:        art.Views,
			CommentCount: int64(len(art.Comments)),
			CreatedAt:    art.CreatedAt,
			UpdatedAt:    art.UpdatedAt,
			AuthorID:     art.AuthorID.Hex(),
			AuthorName:   authorName,
			CategoryID:   art.CategoryID.Hex(),
		})
	}
	return out, nil
}

// GetArticleDetails 根据文章 ID 查详情，附带作者昵称和评论数
func GetArticleDetails(ctx context.Context, articleID string) (*ArticleWithAuthor, error) {
	aid, err := primitive.ObjectIDFromHex(articleID)
	if err != nil {
		return nil, errors.New("invalid article ID")
	}

	artColl := db.Client.Database(db.DBName).Collection("Article")
	// 阅读量自增
	artColl.UpdateOne(ctx, bson.M{"_id": aid}, bson.M{"$inc": bson.M{"views": 1}})

	// 查询已通过的文章
	var art models.Article
	if err := artColl.FindOne(ctx, bson.M{"_id": aid, "status": "approved"}).Decode(&art); err != nil {
		return nil, err
	}

	// 查作者名
	userColl := db.Client.Database(db.DBName).Collection("User")
	var author models.User
	authorName := "未知作者"
	if err := userColl.FindOne(ctx, bson.M{"_id": art.AuthorID}).Decode(&author); err == nil {
		authorName = author.Username
	}

	// 评论数
	commentCount := int64(len(art.Comments))

	return &ArticleWithAuthor{
		ID:           art.ID.Hex(),
		Title:        art.Title,
		Description:  art.Description,
		Content:      art.Content,
		Tags:         art.Tags,
		Status:       art.Status,
		Visibility:   art.Visibility,
		Likes:        art.Likes,
		Views:        art.Views,
		CommentCount: commentCount,
		CreatedAt:    art.CreatedAt,
		UpdatedAt:    art.UpdatedAt,
		AuthorID:     art.AuthorID.Hex(),
		AuthorName:   authorName,
		CategoryID:   art.CategoryID.Hex(),
	}, nil
}

// GetFeedArticles 返回当前用户关注的作者的文章，附带作者昵称
func GetFeedArticles(ctx context.Context, userIDStr string) ([]ArticleWithAuthor, error) {
	uid, err := primitive.ObjectIDFromHex(userIDStr)
	if err != nil {
		return nil, errors.New("invalid user ID")
	}
	userColl := db.Client.Database(db.DBName).Collection("User")
	var u models.User
	if err := userColl.FindOne(ctx, bson.M{"_id": uid}).Decode(&u); err != nil {
		return nil, err
	}
	if len(u.Following) == 0 {
		return nil, nil
	}

	artColl := db.Client.Database(db.DBName).Collection("Article")
	cursor, err := artColl.Find(ctx, bson.M{
		"authorId": bson.M{"$in": u.Following},
		"status":   "approved",
		"$or":      []bson.M{{"visibility": "public"}, {"visibility": "followers"}},
	})
	if err != nil {
		return nil, err
	}
	defer cursor.Close(ctx)

	var out []ArticleWithAuthor
	for cursor.Next(ctx) {
		var art models.Article
		if err := cursor.Decode(&art); err != nil {
			continue
		}
		// 查作者名
		var author models.User
		authorName := "未知作者"
		if err := userColl.FindOne(ctx, bson.M{"_id": art.AuthorID}).Decode(&author); err == nil {
			authorName = author.Username
		}
		out = append(out, ArticleWithAuthor{
			ID:           art.ID.Hex(),
			Title:        art.Title,
			Description:  art.Description,
			Content:      art.Content,
			Tags:         art.Tags,
			Status:       art.Status,
			Visibility:   art.Visibility,
			Likes:        art.Likes,
			Views:        art.Views,
			CommentCount: int64(len(art.Comments)),
			CreatedAt:    art.CreatedAt,
			UpdatedAt:    art.UpdatedAt,
			AuthorID:     art.AuthorID.Hex(),
			AuthorName:   authorName,
			CategoryID:   art.CategoryID.Hex(),
		})
	}
	return out, nil
}

// GetLikedArticles 返回当前用户点赞的文章，附带作者昵称
func GetLikedArticles(ctx context.Context, userIDStr string) ([]ArticleWithAuthor, error) {
	uid, err := primitive.ObjectIDFromHex(userIDStr)
	if err != nil {
		return nil, errors.New("invalid user ID")
	}
	likeColl := db.Client.Database(db.DBName).Collection("ArticleLike")
	cursor, err := likeColl.Find(ctx, bson.M{"userId": uid})
	if err != nil {
		return nil, err
	}
	defer cursor.Close(ctx)

	var articleIDs []primitive.ObjectID
	for cursor.Next(ctx) {
		var rec struct {
			ArticleID primitive.ObjectID `bson:"articleId"`
		}
		if err := cursor.Decode(&rec); err != nil {
			continue
		}
		articleIDs = append(articleIDs, rec.ArticleID)
	}
	if len(articleIDs) == 0 {
		return nil, nil
	}

	artColl := db.Client.Database(db.DBName).Collection("Article")
	cursor2, err := artColl.Find(ctx, bson.M{"_id": bson.M{"$in": articleIDs}, "status": "approved"})
	if err != nil {
		return nil, err
	}
	defer cursor2.Close(ctx)

	userColl := db.Client.Database(db.DBName).Collection("User")
	var out []ArticleWithAuthor
	for cursor2.Next(ctx) {
		var art models.Article
		if err := cursor2.Decode(&art); err != nil {
			continue
		}
		var author models.User
		authorName := "未知作者"
		if err := userColl.FindOne(ctx, bson.M{"_id": art.AuthorID}).Decode(&author); err == nil {
			authorName = author.Username
		}
		out = append(out, ArticleWithAuthor{
			ID:           art.ID.Hex(),
			Title:        art.Title,
			Description:  art.Description,
			Content:      art.Content,
			Tags:         art.Tags,
			Status:       art.Status,
			Visibility:   art.Visibility,
			Likes:        art.Likes,
			Views:        art.Views,
			CommentCount: int64(len(art.Comments)),
			CreatedAt:    art.CreatedAt,
			UpdatedAt:    art.UpdatedAt,
			AuthorID:     art.AuthorID.Hex(),
			AuthorName:   authorName,
			CategoryID:   art.CategoryID.Hex(),
		})
	}
	return out, nil
}

// GetPendingArticles 返回待审文章列表，附带作者昵称
func GetPendingArticles(ctx context.Context) ([]ArticleWithAuthor, error) {
	artColl := db.Client.Database(db.DBName).Collection("Article")
	cursor, err := artColl.Find(ctx, bson.M{"status": "pending"})
	if err != nil {
		return nil, err
	}
	defer cursor.Close(ctx)

	userColl := db.Client.Database(db.DBName).Collection("User")
	var out []ArticleWithAuthor
	for cursor.Next(ctx) {
		var art models.Article
		if err := cursor.Decode(&art); err != nil {
			continue
		}
		var author models.User
		authorName := "未知作者"
		if err := userColl.FindOne(ctx, bson.M{"_id": art.AuthorID}).Decode(&author); err == nil {
			authorName = author.Username
		}
		out = append(out, ArticleWithAuthor{
			ID:           art.ID.Hex(),
			Title:        art.Title,
			Description:  art.Description,
			Content:      art.Content,
			Tags:         art.Tags,
			Status:       art.Status,
			Visibility:   art.Visibility,
			Likes:        art.Likes,
			Views:        art.Views,
			CommentCount: int64(len(art.Comments)),
			CreatedAt:    art.CreatedAt,
			UpdatedAt:    art.UpdatedAt,
			AuthorID:     art.AuthorID.Hex(),
			AuthorName:   authorName,
			CategoryID:   art.CategoryID.Hex(),
		})
	}
	return out, nil
}
